<

トラックパッドのジェスチャで GestureRecognizer をトリガーできる

まとめ

ほとんどのプラットフォームでトラックパッド ジェスチャが送信されるようになりましたPointerPanZoomシーケンスと パン、ドラッグ、スケールをトリガーできますGestureRecognizerコールバック。

コンテクスト

バージョン 3.3.0 より前の Flutter Desktop でのスクロールPointerScrollEvent離散スクロール デルタを表すメッセージ。このシステムはマウスでうまく機能しました スクロールホイールもありましたが、トラックパッドのスクロールには適していませんでした。トラックパッドのスクロール 勢いはスクロールデルタだけではなく、 トラックパッドから指を離すタイミングも同様です。 また、トラックパッドのピンチによるズームも表現できませんでした。

3つの新しいPointerEventが導入されました:PointerPanZoomStartEventPointerPanZoomUpdateEvent、 とPointerPanZoomEndEvent。 関連するGestureRecognizerへの関心を登録するために更新されました トラックパッド ジェスチャ シーケンス、および放出されますonDragonPan、および/またはonScale動きに応じたコールバック トラックパッド上で 2 本以上の指で操作します。

これは、タッチ操作専用に設計されたコードが、次のような場合にトリガーされる可能性があることを意味します。 トラックパッドの操作と、すべてのデスクトップのスクロールを処理するように設計されたコード トラックパッドのスクロールではなく、マウスのスクロール時にのみトリガーされるようになりました。

変更内容の説明

Flutter エンジンは、すべてのプラットフォームで認識できるように更新されました。 トラックパッド ジェスチャを取得し、それを次のようにフレームワークに送信します。PointerPanZoomイベント としてではなくPointerScrollSignalイベント。PointerScrollSignalイベントは マウスホイールのスクロールを表すために今でも使用されています。

プラットフォームと特定のトラックパッド モデルによっては、新しいシステムが機能しない可能性があります。 プラットフォーム API によって Flutter エンジンに十分なデータが提供されない場合に使用されます。 これには Windows も含まれます。Windows では、トラックパッド ジェスチャのサポートは トラックパッドのドライバーと Web プラットフォームでは、十分なデータが提供されません。 ブラウザ API とトラックパッドのスクロールは依然として必要です 古いものを使うPointerScrollSignalシステム。

開発者は、両方のタイプのイベントを受け取る準備をしておく必要があります。 アプリまたはパッケージが適切な方法でそれらを処理することを確認します。

Listenerには 3 つの新しいコールバックが追加されました。onPointerPanZoomStartonPointerPanZoomUpdate、 とonPointerPanZoomEndどれができるか トラックパッドのスクロールおよびズーム イベントを観察するために使用されます。

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerSignal: (PointerSignalEvent event) {
        if (event is PointerScrollEvent) {
          debugPrint('mouse scrolled ${event.scrollDelta}');
        }
      },
      onPointerPanZoomStart: (PointerPanZoomStartEvent event) {
        debugPrint('trackpad scroll started');
      },
      onPointerPanZoomUpdate: (PointerPanZoomUpdateEvent event) {
        debugPrint('trackpad scrolled ${event.panDelta}');
      },
      onPointerPanZoomEnd: (PointerPanZoomEndEvent event) {
        debugPrint('trackpad scroll ended');
      },
      child: Container()
    );
  }
}

PointerPanZoomUpdateEventが含まれていますpan累積を表すフィールド 現在のジェスチャのパン、panDelta違いを表すフィールド 最後のイベント以降のパン、scale累積ズームを表すイベント 現在のジェスチャの、およびrotationイベントへ 現在のジェスチャの累積回転 (ラジアン単位) を表します。

GestureRecognizer1 つのトラックパッド イベントに対するすべてのメソッドが追加されました。 連続トラックパッドジェスチャ。電話をかけるaddPointerPanZoomのメソッドGestureRecognizerとともにPointerPanZoomStartEvent認識機能が発生します トラックパッドのインタラクションへの関心を登録し、競合を解決します。 複数の間GestureRecognizerに応答する可能性のあるもの ジェスチャー。

次の例は、の適切な使用法を示しています。ListenerGestureRecognizerトラックパッドの操作に応答します。

void main() => runApp(Foo());

class Foo extends StatefulWidget {
  late final PanGestureRecognizer recognizer;

  @override
  void initState() {
    super.initState();
    recognizer = PanGestureRecognizer()
    ..onStart = _onPanStart
    ..onUpdate = _onPanUpdate
    ..onEnd = _onPanEnd;
  }

  void _onPanStart(DragStartDetails details) {
    debugPrint('onStart');
  }

  void _onPanUpdate(DragUpdateDetails details) {
    debugPrint('onUpdate');
  }

  void _onPanEnd(DragEndDetails details) {
    debugPrint('onEnd');
  }

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: recognizer.addPointer,
      onPointerPanZoomStart: recognizer.addPointerPanZoom,
      child: Container()
    );
  }
}

使用するときGestureDetector、これは自動的に行われるため、次のようなコードを記述します。 次の例では、両方の応答に応じてジェスチャ更新コールバックを発行します。 タッチとトラックパッドのパン。

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanStart: (details) {
        debugPrint('onStart');
      },
      onPanUpdate: (details) {
        debugPrint('onUpdate');
      },
      onPanEnd: (details) {
        debugPrint('onEnd');
      }
      child: Container()
    );
  }
}

移行ガイド

移行手順は、各ジェスチャ操作を必要かどうかによって異なります。 アプリをトラックパッド経由で使用できるようにするか、またはトラックパッドのみに制限する必要があるか タッチとマウスの使い方。

トラックパッドの使用に適したジェスチャ操作用

使用するGestureDetector

変更の必要はありませんが、GestureDetectorトラックパッドを自動的に処理する ジェスチャ イベントを生成し、認識された場合はコールバックをトリガーします。

使用するGestureRecognizerListener

確認しておいてonPointerPanZoomStartに渡されます からの各認識器Listener。 のaddPointerPanZoom`GestureRecognizer のメソッドを呼び出す必要があります 興味を示し、各トラックパッドのジェスチャの追跡を開始します。

移行前のコード:

void main() => runApp(Foo());

class Foo extends StatefulWidget {
  late final PanGestureRecognizer recognizer;

  @override
  void initState() {
    super.initState();
    recognizer = PanGestureRecognizer()
    ..onStart = _onPanStart
    ..onUpdate = _onPanUpdate
    ..onEnd = _onPanEnd;
  }

  void _onPanStart(DragStartDetails details) {
    debugPrint('onStart');
  }

  void _onPanUpdate(DragUpdateDetails details) {
    debugPrint('onUpdate');
  }

  void _onPanEnd(DragEndDetails details) {
    debugPrint('onEnd');
  }

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: recognizer.addPointer,
      child: Container()
    );
  }
}

移行後のコード:

void main() => runApp(Foo());

class Foo extends StatefulWidget {
  late final PanGestureRecognizer recognizer;

  @override
  void initState() {
    super.initState();
    recognizer = PanGestureRecognizer()
    ..onStart = _onPanStart
    ..onUpdate = _onPanUpdate
    ..onEnd = _onPanEnd;
  }

  void _onPanStart(DragStartDetails details) {
    debugPrint('onStart');
  }

  void _onPanUpdate(DragUpdateDetails details) {
    debugPrint('onUpdate');
  }

  void _onPanEnd(DragEndDetails details) {
    debugPrint('onEnd');
  }

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: recognizer.addPointer,
      onPointerPanZoomStart: recognizer.addPointerPanZoom,
      child: Container()
    );
  }
}

生で使用するListener

PointerScrollSignal を使用する次のコードは、すべての場合に呼び出されなくなります。 デスクトップのスクロール。PointerPanZoomUpdate受信するにはイベントをキャプチャする必要があります トラックパッドのジェスチャ データ。

移行前のコード:

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerSignal: (PointerSignalEvent event) {
        if (event is PointerScrollEvent) {
          debugPrint('scroll wheel event');
        }
      }
      child: Container()
    );
  }
}

移行後のコード:

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerSignal: (PointerSignalEvent event) {
        if (event is PointerScrollEvent) {
          debugPrint('scroll wheel event');
        }
      },
      onPointerPanZoomUpdate: (PointerPanZoomUpdateEvent event) {
        debugPrint('trackpad scroll event');
      }
      child: Container()
    );
  }
}

ご注意:生のままの使用Listenerこのようにして 他のジェスチャ インタラクションと競合が発生するため、 ジェスチャー曖昧さ回避の分野には参加しません。

トラックパッドの使用に適さないジェスチャ操作の場合

使用するGestureDetector

Flutter 3.3.0を使用している場合、RawGestureDetector使用することができます それ以外のGestureDetectorそれぞれを確実にするためにGestureRecognizer作成した によってGestureDetectorもっているsupportedDevicesに設定 除外するPointerDeviceKind.trackpad。 バージョン 3.4.0 以降、supportedDevicesパラメータ 直接1283219d-146a-4a7e-a​​e37-ee3289eb73d6。

移行前のコード:

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onPanStart: (details) {
        debugPrint('onStart');
      },
      onPanUpdate: (details) {
        debugPrint('onUpdate');
      },
      onPanEnd: (details) {
        debugPrint('onEnd');
      }
      child: Container()
    );
  }
}

移行後のコード (Flutter 3.3.0):

// Example of code after the change.
void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RawGestureDetector(
      gestures: {
        PanGestureRecognizer:
            GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>(
          () => PanGestureRecognizer(
            supportedDevices: {
              PointerDeviceKind.touch,
              PointerDeviceKind.mouse,
              PointerDeviceKind.stylus,
              PointerDeviceKind.invertedStylus,
              // Do not include PointerDeviceKind.trackpad
            }
          ),
          (recognizer) {
            recognizer
              ..onStart = (details) {
                debugPrint('onStart');
              }
              ..onUpdate = (details) {
                debugPrint('onUpdate');
              }
              ..onEnd = (details) {
                debugPrint('onEnd');
              };
          },
        ),
      },
      child: Container()
    );
  }
}

移行後のコード: (Flutter 3.4.0):

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      supportedDevices: {
        PointerDeviceKind.touch,
        PointerDeviceKind.mouse,
        PointerDeviceKind.stylus,
        PointerDeviceKind.invertedStylus,
        // Do not include PointerDeviceKind.trackpad
      },
      onPanStart: (details) {
        debugPrint('onStart');
      },
      onPanUpdate: (details) {
        debugPrint('onUpdate');
      },
      onPanEnd: (details) {
        debugPrint('onEnd');
      }
      child: Container()
    );
  }
}

使用するRawGestureRecognizer

次のことを明示的に保証しますsupportedDevices含まないPointerDeviceKind.trackpad

移行前のコード:

void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RawGestureDetector(
      gestures: {
        PanGestureRecognizer:
            GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>(
          () => PanGestureRecognizer(),
          (recognizer) {
            recognizer
              ..onStart = (details) {
                debugPrint('onStart');
              }
              ..onUpdate = (details) {
                debugPrint('onUpdate');
              }
              ..onEnd = (details) {
                debugPrint('onEnd');
              };
          },
        ),
      },
      child: Container()
    );
  }
}

移行後のコード:

// Example of code after the change.
void main() => runApp(Foo());

class Foo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return RawGestureDetector(
      gestures: {
        PanGestureRecognizer:
            GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>(
          () => PanGestureRecognizer(
            supportedDevices: {
              PointerDeviceKind.touch,
              PointerDeviceKind.mouse,
              PointerDeviceKind.stylus,
              PointerDeviceKind.invertedStylus,
              // Do not include PointerDeviceKind.trackpad
            }
          ),
          (recognizer) {
            recognizer
              ..onStart = (details) {
                debugPrint('onStart');
              }
              ..onUpdate = (details) {
                debugPrint('onUpdate');
              }
              ..onEnd = (details) {
                debugPrint('onEnd');
              };
          },
        ),
      },
      child: Container()
    );
  }
}

使用するGestureRecognizerListener

Flutter 3.3.0 にアップグレードしても、動作に変化はありません。お父さん78cd2-496d-4661-b6ad-d16604a33473それぞれで呼び出す必要がありますGestureRecognizer許可する ジェスチャーを追跡するために使用します。次のコードはパン ジェスチャのコールバックを受け取りません トラックパッドがスクロールされたとき:

void main() => runApp(Foo());

class Foo extends StatefulWidget {
  late final PanGestureRecognizer recognizer;

  @override
  void initState() {
    super.initState();
    recognizer = PanGestureRecognizer()
    ..onStart = _onPanStart
    ..onUpdate = _onPanUpdate
    ..onEnd = _onPanEnd;
  }

  void _onPanStart(DragStartDetails details) {
    debugPrint('onStart');
  }

  void _onPanUpdate(DragUpdateDetails details) {
    debugPrint('onUpdate');
  }

  void _onPanEnd(DragEndDetails details) {
    debugPrint('onEnd');
  }

  @override
  Widget build(BuildContext context) {
    return Listener(
      onPointerDown: recognizer.addPointer,
      // recognizer.addPointerPanZoom is not called
      child: Container()
    );
  }
}

タイムライン

リリースされたバージョン: 3.3.0-0.0.pre 安定リリース: 3.3.0

参考文献

API ドキュメント:

  • GestureDetector
  • RawGestureDetector
  • GestureRecognizer

設計書:

  • Flutter トラックパッド ジェスチャー

関連する問題:

  • 問題 23604

関連する PR:

  • フレームワークでトラックパッド ジェスチャをサポートする
  • iPadのトラックパッドのジェスチャー
  • Linux トラックパッド ジェスチャ
  • Mac のトラックパッド ジェスチャ
  • Win32 トラックパッド ジェスチャ
  • ChromeOS/Android トラックパッド ジェスチャ